
// 类型检查器
//利用接口属性、interface可以剔除对象中的其它不相关属性
interface nameValue {
    name:string
}
let printName = function (nameObj: nameValue) {
    console.log(nameObj.name)
}
let obj = {n:100,name:"零三"}
printName(obj)


// 可选属性
interface itf2 {
    color?:string,
    num?:number
}
function f1(config:itf2) : {color:string; num:number} {
    let newItf2 = {color: "red", num:30}
    if (config.color)
        newItf2.color = config.color
    if (config.num)
        newItf2.num = config.num
    return newItf2
}
function f2(config:{color?:string,num?:number}) : {color:string; num:number} {
    let newItf2 = {color: "red", num:30}
    if (config.color)
        newItf2.color = config.color
    if (config.num)
        newItf2.num = config.num
    return newItf2
}
let obj11 = f1({color:'white',num:1})
let obj22 = f2({color:'white',num:1})
// 然而，TypeScript会认为这段代码可能存在bug。 对象字面量会被特殊对待而且会经过 额外属性检查，当将它们赋值给变量或作为参数传递的时候。 如果一个对象字面量存在任何“目标类型”不包含的属性时，你会得到一个错误
// let obj33 = f2({color1:'white',num:1})
let obj333 = f2({color1:'white',num:1} as itf2)
console.log(obj11,obj22,obj333)


// 只读属性
interface itf3 {
    readonly x:string,
    readonly y:number
}
let obj3:itf3 = {x:"xx",y:100}
// obj3.x = "xxx" // 不能赋值

// TypeScript具有ReadonlyArray<T>类型，它与Array<T>相似，只是把所有可变方法去掉了，因此可以确保数组创建后再也不能被修改：
let a:number[] = [1,2,1,5]
let ao:ReadonlyArray<number> = a
console.log(ao[0])
a[0]=12
// ao[0]=1//错误
console.log(ao[0])//12

// a=ao//错误
//可以看到就算把整个ReadonlyArray赋值到一个普通数组也是不可以的。 但是你可以用类型断言重写：
a= ao as [number]
console.log(a)



// 函数类型
// 为了使用接口表示函数类型，我们需要给接口定义一个调用签名。 它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。
interface SearchFunc {
    (source: string, subString: string): boolean;
}
// 这样定义后，我们可以像使用其它接口一样使用这个函数类型的接口。 下例展示了如何创建一个函数类型的变量，并将一个同类型的函数赋值给这个变量
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
    let result = source.search(subString);
    return result > -1;
}
// 写法2
let mySearch1: SearchFunc;
mySearch1 = function(src: string, sub: string): boolean {
    let result = src.search(sub);
    return result > -1;
}



// 索引签名
// TypeScript支持两种索引签名：字符串和数字。 可以同时使用两种类型的索引，但是数字索引的返回值必须是字符串索引返回值类型的子类型。 这是因为当使用 number来索引时，JavaScript会将它转换成string然后再去索引对象。 也就是说用 100（一个number）去索引等同于使用"100"（一个string）去索引，因此两者需要保持一致。


interface ReadonlyStringArray {
    readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
// myArray[2] = "Mallory"; // error!
// 你不能设置myArray[2]，因为索引签名是只读的。




// 类类型
//实现接口

// 接口描述了类的公共部分，而不是公共和私有两部分。 它不会帮你检查类是否具有某些私有成员。
interface Itf5 {
    createTime:Date;
}
class Clock implements Itf5{
    // @ts-ignore
    createTime: Date;
    setTime(d:Date){
        this.createTime = d
    }
    constructor(h:number,m:number){

    }
}










interface ClockConstructor {
    new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
    // @ts-ignore
    tick();
}

function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
    return new ctor(hour, minute);
}

class DigitalClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("beep beep");
    }
}
class AnalogClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("tick tock");
    }
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);







// 多继承
interface Itf6 {
   color:string;
}
interface Itf7 {
    num:number;
}
interface Itf8 extends Itf6,Itf7 {
    main:String;
}
let m = <Itf8>{}
m.main = "1"
m.color = "red"
m.num = 123
console.log(m)



// 混合类型
// 先前我们提过，接口能够描述JavaScript里丰富的类型。 因为JavaScript其动态灵活的特点，有时你会希望一个对象可以同时具有上面提到的多种类型。
interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}

function getCounter(): Counter {
    let counter = <Counter>function (start: number) {
        console.log(start)
    };
    counter.interval = 123;
    counter.reset = function () {
        console.log("reset")
    };
    return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;








// 接口继承类
class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control implements SelectableControl {
    select() { }
}

class TextBox extends Control {
    select() { }
}

// 错误：“Image”类型缺少“state”属性。
/*class Image implements SelectableControl {
    select() { }
}*/



























